#include "Database.h"
#include "MiscData.h"
#include <QDebug>

Database *Database::getInstance()
{
    static Database singleton{};
    return &singleton;
}

void Database::createPatientTable()
{
    if (g_initState < 0) {
        qWarning()<<"database not init";
        return;
    }

    if(!g_sqlQuery->exec("create table patientInfoTable(number int primary key,id text UNIQUE , name text, age int, "
                              "birthday text, gender int, visitTime text, phone text, addr text)")) {
        qWarning() << "fail to create patientInfoTable, table may exist:"<<g_sqlQuery->lastError();
    }
}

int Database::addPatient(PatientInfo *info)
{
    if (g_initState < 0) {
        qWarning()<<"database not init";
        return -1;
    }

    if(!g_sqlQuery->exec(QString("INSERT INTO patientInfoTable VALUES(%1, \"%2\", \"%3\", %4, \"%5\", %6, \"%7\", \"%8\", \"%9\")")\
                              .arg(info->number).arg(info->id).arg(info->name).arg(info->age).arg(info->birthday).arg(info->gender)\
                              .arg(info->visitTime).arg(info->phone).arg(info->addr))) {
        qWarning()<<"add patientinfo to patientInfoTable fail:"<<g_sqlQuery->lastError();
        return -1;
    }

    return 0;
}

int Database::deletePatient(int number)
{
    if (g_initState < 0) {
        qWarning()<<"database not init";
        return -1;
    }

    g_sqlQuery->exec(QString("delete from patientInfoTable where number = %1").arg(number));
    if(!g_sqlQuery->exec()) {
        qWarning()<<"detele patientinfo from patientInfoTable fail:"<<g_sqlQuery->lastError();
        return -1;
    }

    return 0;
}

int Database::modifyPatient(PatientInfo *info)
{
    if (g_initState < 0) {
        qWarning()<<"database not init";
        return -1;
    }

    g_sqlQuery->exec(QString("update patientInfoTable set id = \"%1\", name = \"%2\", age = %3, birthday = \"%4\", gender = %5,"
                             "visitTime = \"%6\", phone = \"%7\", addr = \"%8\" where number = %9")\
                          .arg(info->id).arg(info->name).arg(info->age).arg(info->birthday).arg(info->gender)\
                          .arg(info->visitTime).arg(info->phone).arg(info->addr).arg(info->number));
    if(!g_sqlQuery->exec()) {
        qWarning()<<"modify patientInfo from patientInfoTable fail:"<<g_sqlQuery->lastError();
        return -1;
    }

    return 0;
}

int Database::getFreePatientNumber()
{
    QList<int> numberList;

    if (g_initState < 0) {
        qWarning()<<"database not init";
        return -1;
    }

    /* 获取所有number */
    int number = -1;
    g_sqlQuery->exec(QString("select * from patientInfoTable"));
    if(!g_sqlQuery->exec()) {
        qDebug()<<"query all patientInfo form patientInfoTable fail:"<<g_sqlQuery->lastError();
        return -1;
    } else {
        while(g_sqlQuery->next()) {
            number = g_sqlQuery->value(0).toInt();
            numberList.append(number);
        }
    }

    qSort(numberList.begin(), numberList.end());
    for (int i = 0; i < numberList.size(); i++) {
        if (numberList.at(i) == i) {
            continue;
        } else {
            return i;
        }
    }

    return numberList.size();
}

int Database::getMaxPatientNumber()
{
    QSqlRecord rec;
    int maxNumber = -1;

    if (g_initState < 0) {
        qWarning()<<"database not init";
        return -1;
    }

    /* 查找最大的number */
    g_sqlQuery->exec(QString("select * from patientInfoTable where number = (select max(number) from patientInfoTable)"));
    if(!g_sqlQuery->exec()) {
        qDebug()<<"find max patient number failed,"<<g_sqlQuery->lastError();
        return -1;
    } else {
        if (g_sqlQuery->next()) {
            rec = g_sqlQuery->record();
            maxNumber = rec.value("number").toInt();
        }
    }
    qDebug()<<"max number = "<<maxNumber<<" in patient"<<rec.value("name").toString();

    return maxNumber;
}

PatientInfo *Database::queryPatient(int number)
{
    static PatientInfo info;

    info.number = -1;
    if (g_initState < 0) {
        qWarning()<<"database not init";
        return &info;
    }

    g_sqlQuery->exec(QString("select * from patientInfoTable where number = %1").arg(number));
    if(!g_sqlQuery->exec()) {
        qDebug()<<"query patientInfo form patientInfoTable fail, number = "<<number<<":"<<g_sqlQuery->lastError();
        return &info;
    } else {
        while(g_sqlQuery->next()) {
            info.number     = g_sqlQuery->value(0).toInt();
            info.id         = g_sqlQuery->value(1).toString();
            info.name       = g_sqlQuery->value(2).toString();
            info.age        = g_sqlQuery->value(3).toInt();
            info.birthday   = g_sqlQuery->value(4).toString();
            info.gender     = g_sqlQuery->value(5).toInt();
            info.visitTime  = g_sqlQuery->value(6).toString();
            info.phone      = g_sqlQuery->value(7).toString();
            info.addr       = g_sqlQuery->value(8).toString();
        }
    }

    return &info;
}

void Database::freePatientInfo(QList<PatientInfo *> *list)
{
    int size = list->size();
    PatientInfo* info = nullptr;

    for (int i = 0; i < size; i++) {
        info = list->at(i);
        delete info;
        info = nullptr;
    }

    list->clear();
}

QList<PatientInfo *> *Database::queryPatient()
{
    static QList<PatientInfo*> infoList;
    infoList.clear();
    if (g_initState < 0) {
        qWarning()<<"database not init";
        return &infoList;
    }

    g_sqlQuery->exec(QString("select * from patientInfoTable"));
    if(!g_sqlQuery->exec()) {
        qDebug()<<"query all patientInfo form patientInfoTable fail:"<<g_sqlQuery->lastError();
        return &infoList;
    } else {
        while(g_sqlQuery->next()) {
            PatientInfo* info = new PatientInfo();
            infoList.append(info);

            info->number     = g_sqlQuery->value(0).toInt();
            info->id         = g_sqlQuery->value(1).toString();
            info->name       = g_sqlQuery->value(2).toString();
            info->age        = g_sqlQuery->value(3).toInt();
            info->birthday   = g_sqlQuery->value(4).toString();
            info->gender     = g_sqlQuery->value(5).toInt();
            info->visitTime  = g_sqlQuery->value(6).toString();
            info->phone      = g_sqlQuery->value(7).toString();
            info->addr       = g_sqlQuery->value(8).toString();
        }
    }

    return &infoList;
}

QList<PatientInfo *> *Database::queryPatient(const QString &type){
    static QList<PatientInfo*> infoList;
    infoList.clear();
    if (g_initState < 0) {
        qWarning()<<"database not init";
        return &infoList;
    }

    g_sqlQuery->exec(QString("select * from patientInfoTable WHERE %1").arg(type));
    if(!g_sqlQuery->exec()) {
        qDebug()<<"query all patientInfo form patientInfoTable fail:"<<g_sqlQuery->lastError();
        return &infoList;
    } else {
        while(g_sqlQuery->next()) {
            PatientInfo* info = new PatientInfo();
            infoList.append(info);

            info->number     = g_sqlQuery->value(0).toInt();
            info->id         = g_sqlQuery->value(1).toString();
            info->name       = g_sqlQuery->value(2).toString();
            info->age        = g_sqlQuery->value(3).toInt();
            info->birthday   = g_sqlQuery->value(4).toString();
            info->gender     = g_sqlQuery->value(5).toInt();
            info->visitTime  = g_sqlQuery->value(6).toString();
            info->phone      = g_sqlQuery->value(7).toString();
            info->addr       = g_sqlQuery->value(8).toString();
        }
    }

    return &infoList;
}

Database::Database()
{
    g_database = QSqlDatabase::addDatabase("QSQLITE");
    g_database.setDatabaseName("database/database.db");
    g_sqlQuery = new QSqlQuery(g_database);

    if (!g_database.open()) {
        g_initState = -1;
        RuntimeData::MiscData::getInstance()->g_miscDataInfo.databaseInitState = -1;
        qWarning()<<"failed to connect database: database/database.db, "<<g_database.lastError();
    } else {
        g_initState = 0;
        RuntimeData::MiscData::getInstance()->g_miscDataInfo.databaseInitState = 0;
    }
    createPatientTable();
}
